package Project;
import java.awt.Color;
import java.util.ArrayList;

import Hulppakket.*;
public class Shader {
	private ArrayList<Light> lights;
	private static Color3f background = new Color3f(0F,0F,0F);
	private static float epsilon = 0.01F;
	// Implicit assumption: ambient color = surface color, specular color = surface independent
	private static Color3f specularColor = new Color3f(0.5F,0.5F,0.5F);

	private float ambientIntensity = 0.1F;
	public Shader() {
		lights = new ArrayList<Light>();
	}
	public Shader(ArrayList<Light> newlights) {
		lights = new ArrayList<Light>();
		this.setLights(newlights);
	}
	public Shader(ArrayList<Light> newlights, float ambientIntensity) {
		lights = new ArrayList<Light>();
		this.setLights(newlights);
		this.setAmbientIntensity(ambientIntensity);
	}

	// Moet dit uiteindelijk met een Surface of met een Scene?
	public Color3f raycolor(Ray r, float t0, float t1, Surface s) {
		Hitrecord h1 = new Hitrecord();
		Hitrecord h2 = new Hitrecord();
		if(s.hit(r, t0, t1, h1)) {
			Color3f c = Color3f.Multiply(h1.color,this.getAmbientIntensity());
			for(int i = 0; i < this.getLights().size(); i ++) {
				Light light = this.getLights().get(i);
				// TODO: this should be left out of the final version!
				Vector3f l = Point3f.Min(light.getOrigin(),h1.intersection);
				float distance = (float) Math.sqrt(Vector3f.Inp(l, l));
				l = l.normalise();
				Ray shadow = new Ray(h1.intersection,l);
				if(!s.hit(shadow, epsilon,distance,h2)) {
					Vector3f h = Vector3f.Plus(l.normalise(), r.getDirection().multiply(-1F).normalise());
					h = h.normalise();
					// diffuse shading
					c = Color3f.Plus(c, Color3f.Multiply(h1.color, light.getIntensity()*Math.max(0,Vector3f.Inp(h1.normal, l))));
					// specular shading
					c = Color3f.Plus(c, Color3f.Multiply(specularColor, (float) (light.getIntensity()*Math.pow(Vector3f.Inp(h1.normal, h),light.getPhongexp()))));
					c = c.normalise();
				}
			}
			return c;
		}
		else {
			return background;
		}
	}
	private float getInfinity() {
		return 100000F;
	}
	public void addLight(Light light1) {
		lights.add(light1);
	}
	public ArrayList<Light> getLights() {
		return lights;
	}

	public void setLights(ArrayList<Light> lights) {
		this.lights = lights;
	}

	public float getAmbientIntensity() {
		return ambientIntensity;
	}

	public void setAmbientIntensity(float ambientIntensity) {
		this.ambientIntensity = ambientIntensity;
	}
}
